package com.wsm.common.aspect;

import com.wsm.common.annotation.DuplicateSubmitToken;
import com.wsm.common.exception.DuplicateSubmitException;
import com.wsm.common.service.RedisService;
import com.wsm.common.utils.AspectUtil;
import com.wsm.common.utils.IPUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

import static com.wsm.common.enums.Constant.DUPLICATE_TOKEN_KEY;

/**
 * @name: DuplicateSubmitAspect
 * @Author: wangshimin
 * @Date: 2020/2/8  16:13
 * @Description:防止表单重复提交拦截器
 */
@Aspect
@Component
@Slf4j
@Order(2)
public class DuplicateSubmitAspect {
    @Autowired
    RedisService redisService;

    @Pointcut(value = "@annotation(com.wsm.common.annotation.DuplicateSubmitToken)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        Method currentMethod = AspectUtil.getMethod(joinPoint);
        DuplicateSubmitToken annotation = currentMethod.getAnnotation(DuplicateSubmitToken.class);
        boolean isSaveSession = annotation.save();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String key = DUPLICATE_TOKEN_KEY + IPUtils.getIpAddr(request) + AspectUtil.getKey(joinPoint, DUPLICATE_TOKEN_KEY);
        if (isSaveSession) {
            boolean hasKey = redisService.hasKey(key);
            if (hasKey) {
                throw new DuplicateSubmitException("正在处理，请稍后");
            } else {
                redisService.set(key, null, annotation.expire(), annotation.time());
            }
        }
        Object proceed;
        try {
            proceed = joinPoint.proceed();
        } finally {
            if (isSaveSession) {
                if (redisService.hasKey(key)) {
                    redisService.del(key);
                }
            }
        }
        return proceed;
    }
}
